package com.xyy.saas.payment.adpater.wechat;

import com.alibaba.fastjson.JSON;
import com.xyy.saas.payment.adpater.pingxx.domain.PayDO;
import com.xyy.saas.payment.adpater.pingxx.domain.RefundDO;
import com.xyy.saas.payment.callback.core.handler.CastRequestHandler;
import com.xyy.saas.payment.common.Constants;
import com.xyy.saas.payment.config.YkqWxConfig;
import com.xyy.saas.payment.dao.model.RefundOrder;
import com.xyy.saas.payment.util.*;
import org.apache.commons.lang.StringUtils;
import org.dom4j.DocumentException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
import sun.misc.BASE64Decoder;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: wuqiongda
 * @Date: 2019/12/17 19:14
 */
@Component
@Deprecated
@DependsOn("apolloUtil")
public class CastWXRequestHandler implements CastRequestHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(CastWXRequestHandler.class);

    @Autowired
    YkqWxConfig ykqWxConfig;
    Map<String, String> keyMap = new HashMap<>();
    {
        keyMap.put("1578283921", ApolloUtil.getProperty("yikuaiqian_doc.wx.newkey"));
        keyMap.put("1566654551", ApolloUtil.getProperty("yikuaiqian_doc.wx.key"));
    }
    @Override
    public String getChannel() {
        return Constants.CHANNEL_WX_NAME;
    }

    @Override
    public Object castRequestHandler(String method, Map<String, String> request, HttpServletRequest requestMsg) throws Exception {
        Object domain = null;
        switch (method) {
            case Constants.METHOD_WXPAY_SUCCESS_NAME:
                domain = castToPayDo(request);
                return domain;
            case Constants.METHOD_REFUND_SUCCESS:
                domain = castToRefundDO(request);
                return domain;
            default:
                break;
        }
        return null;
    }

    private Map<String, String> getObjectFromWx(Map<String, String> request) {
        try {
            Map<String, String> map = WxUtil.doXMLParse(request.get("post-val"));
            return map;
        } catch (Exception e) {
            LOGGER.error("CastWXRequestHandler getObjectFromWx fail request:{}", JSON.toJSON(request), e);
            return null;
        }
    }

    /**
     * charge 对象
     *
     * @param request
     * @return
     */
    private PayDO castToPayDo(Map<String, String> request) {
        Map<String, String> map = getObjectFromWx(request);
        if (map == null) {
            return null;
        }
        String payNo = map.get("out_trade_no");
        String tradeNo = map.get("transaction_id");
        Integer fee = Integer.parseInt(map.get("total_fee"));
        //透传参数
        String passbackParams = map.get("attach");
        Map<String, String> attach = JSONUtils.parse2Map(passbackParams, String.class, String.class);
        String businessType = attach.get("business_type");
        String businessOrderType = attach.get("business_order_type");
        String receiverId = attach.get("receiver_id");
        String callbackAddress = attach.get("callback_address");
        String returnCode = map.get("return_code");
        String resultCode = map.get("result_code");
        String mchId = map.get("mch_id");
        String tradeTime = map.get("time_end");
        PayDO domain = new PayDO();
        domain.setOrderNo(payNo);
        domain.setChannelChargeNo(tradeNo);
        domain.setAmount(fee);
        domain.setBusinessType(businessType);
        domain.setBusinessOrderType(businessOrderType);
        domain.setReceiverId(receiverId);
        domain.setCallbackAddress(callbackAddress);
        domain.setReturnCode(returnCode);
        domain.setResultCode(resultCode);
        domain.setMchId(mchId);

        try {
            if(!StringUtils.isBlank(tradeTime)) {
                domain.setTimePaid(DateUtil.parase(tradeTime, DateUtil.YYYYMMDDHHMMSS));
            }
        }
        catch(Exception e) {
            LOGGER.error("CastWXRequestHandler#castToPayDo cast time error request:{}", JSON.toJSONString(request));
        }

        return domain;
    }

    /**
     * 退款对象
     *
     * @param request
     * @return
     */
    private RefundDO castToRefundDO(Map<String, String> request) {
        Map<String, String> refund = getObjectFromWx(request);
        if (refund == null) {
            return null;
        }
        // 解密加密信息
        String mchId = refund.get("mch_id");
        String reqInfo = decryptData(refund.get("req_info"), mchId);
        if(reqInfo == null) {
            return null;
        }
        Map<String, String> refundMap = null;
        try {
            refundMap = WxUtil.doXMLParse(reqInfo);
        } catch (DocumentException e) {
            LOGGER.error("CastWXRequestHandler#castToRefundDO cast xml error request:{} ", JSON.toJSONString(request), e);
            return null;
        }
        RefundDO domain = new RefundDO();
        domain.setId(refundMap.get("refund_id"));
        domain.setOrderNo(refundMap.get("out_refund_no"));
        domain.setSucceed("SUCCESS".equals(refundMap.get("refund_status")));
        if (domain.getSucceed()) {
            domain.setStatus(RefundOrder.STATUS_FINISH);
        } else if ("CHANGE".equals(refundMap.get("refund_status"))) {
            domain.setStatus(RefundOrder.STATUS_FAIL);
        } else if ("REFUNDCLOSE".equals(refundMap.get("refund_status"))) {
            domain.setStatus(RefundOrder.STATUS_CLOSED);
        }
        domain.setTimeSucceed(domain.getSucceed() ? DateUtil.sdf1ToDate(refundMap.get("success_time")) : Constants.DEFAULT_DATE);
        domain.setDescription("");
        domain.setExtra("");
        domain.setPayNo(refundMap.get("out_trade_no"));
        domain.setRefundNo(refundMap.get("out_refund_no"));
        return domain;
    }


    /**
     * 密钥算法
     */
    private static final String ALGORITHM = "AES";
    /**
     * 加解密算法
     */
    private static final String ALGORITHM_MODE_PADDING = "AES/ECB/PKCS5Padding";


    public static byte[] decode(String key) throws Exception {
        return new BASE64Decoder().decodeBuffer(key);
    }

    /**
     * 根据商户密钥
     */
    private String decryptData(String base64Data, String mchId) {
        try {
            SecretKeySpec key = new SecretKeySpec(SignUtil.mD5Encode(keyMap.get(mchId)).toLowerCase().getBytes(), ALGORITHM);
            Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING);
            cipher.init(Cipher.DECRYPT_MODE, key);
            return new String(cipher.doFinal(decode(base64Data)), "UTF-8");
        } catch (Exception e) {
            LOGGER.error("CastWXRequestHandler#decryptData decrypt error base64Data:{}", base64Data);
            return null;
        }
    }

}

